#include "hdl_gpio.h"

HDL_GPIO_TYPEDEF hdl_gpio_pinread(GPIO_Type *base, uint32_t pin)
{
	return (HDL_GPIO_TYPEDEF)(((base->DR) >> pin) & 0x1);
}

int8_t hdl_gpio_pinwrite(GPIO_Type *base, uint32_t pin, HDL_GPIO_TYPEDEF value)
{
	if (value == 0U)
	{
		base->DR &= ~(1U << pin);
	}
	else
	{
		base->DR |= (1U << pin);
	}
	return SUCCESS;
}

void hdl_gpio_int_cfg(GPIO_Type* base, unsigned int pin, gpio_interrupt_mode_t pin_int_mode)
{
	volatile uint32_t *icr;
	uint32_t icrShift;

	icrShift = pin;
	
	base->EDGE_SEL &= ~(1U << pin);

	if(pin < 16) 	/* 低16位 */
	{
		icr = &(base->ICR1);
	}
	else			/* 高16位 */
	{
		icr = &(base->ICR2);
		icrShift -= 16;
	}
	switch(pin_int_mode)
	{
		case(kGPIO_IntLowLevel):
			*icr &= ~(3U << (2 * icrShift));
			break;
		case(kGPIO_IntHighLevel):
			*icr = (*icr & (~(3U << (2 * icrShift)))) | (1U << (2 * icrShift));
			break;
		case(kGPIO_IntRisingEdge):
			*icr = (*icr & (~(3U << (2 * icrShift)))) | (2U << (2 * icrShift));
			break;
		case(kGPIO_IntFallingEdge):
			*icr |= (3U << (2 * icrShift));
			break;
		case(kGPIO_IntRisingOrFallingEdge):
			base->EDGE_SEL |= (1U << pin);
			break;
		default:
			break;
	}
}

int8_t hdl_gpio_int_enable(GPIO_Type* base, unsigned int pin)
{ 
    base->IMR |= (1 << pin);
}

int8_t hdl_gpio_int_disable(GPIO_Type* base, unsigned int pin)
{ 
    base->IMR &= ~(1 << pin);
}

int8_t hdl_gpio_int_clr(GPIO_Type* base, unsigned int pin)
{
    base->ISR |= (1 << pin);
}

int8_t hdl_gpio_init(GPIO_Type *base, uint32_t pin, hdl_gpio_StructInit *config)
{
	base->IMR &= ~(1U << pin);
	if(config->direction == GPIO_IN)
	{
		base->GDIR &= ~( 1 << pin);
	}
	else
	{
		base->GDIR |= 1 << pin;
		hdl_gpio_pinwrite(base,pin, config->output);
	}
	hdl_gpio_int_cfg(base, pin, config->interruptMode);	/* 中断功能配置 */
	return SUCCESS;
}

struct hal_gpio_if g_hdl_gpio_if = 
{
    .gpio_init = hdl_gpio_init,
    .gpio_write = hdl_gpio_pinwrite,
    .gpio_read = hdl_gpio_pinread,
	.gpio_int_enable = hdl_gpio_int_enable,
	.gpio_int_disable = hdl_gpio_int_disable,
	.gpio_int_clr = hdl_gpio_int_clr,
};
